home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLUT / win32_menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  11.6 KB  |  526 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
  3. /* Copyright (c) Nate Robins, 1997. */
  4.  
  5. /* This program is freely distributable without licensing fees
  6.    and is provided without guarantee or warrantee expressed or
  7.    implied. This program is -not- in the public domain. */
  8.  
  9. /* This file completely re-implements glut_menu.c and glut_menu2.c
  10.    for Win32.  Note that neither glut_menu.c nor glut_menu2.c are
  11.    compiled into Win32 GLUT. */
  12.  
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <errno.h>
  17. #include <assert.h>
  18.  
  19. #include "glutint.h"
  20.  
  21. void (*__glutMenuStatusFunc) (int, int, int);
  22. GLUTmenu *__glutMappedMenu;
  23. GLUTwindow *__glutMenuWindow;
  24. GLUTmenuItem *__glutItemSelected;
  25. unsigned __glutMenuButton;
  26.  
  27. static GLUTmenu **menuList = NULL;
  28. static int menuListSize = 0;
  29. static UINT uniqueMenuHandler = 1;
  30.  
  31. /* DEPRICATED, use glutMenuStatusFunc instead. */
  32. void APIENTRY
  33. glutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
  34. {
  35.   __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
  36. }
  37.  
  38. void APIENTRY
  39. glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
  40. {
  41.   __glutMenuStatusFunc = menuStatusFunc;
  42. }
  43.  
  44. void
  45. __glutSetMenu(GLUTmenu * menu)
  46. {
  47.   __glutCurrentMenu = menu;
  48. }
  49.  
  50. static void
  51. unmapMenu(GLUTmenu * menu)
  52. {
  53.   if (menu->cascade) {
  54.     unmapMenu(menu->cascade);
  55.     menu->cascade = NULL;
  56.   }
  57.   menu->anchor = NULL;
  58.   menu->highlighted = NULL;
  59. }
  60.  
  61. void
  62. __glutFinishMenu(Window win, int x, int y)
  63. {
  64.  
  65.   unmapMenu(__glutMappedMenu);
  66.  
  67.   /* XXX Put in a GdiFlush just in case.  Probably unnecessary. -mjk  */
  68.   GdiFlush();
  69.  
  70.   if (__glutMenuStatusFunc) {
  71.     __glutSetWindow(__glutMenuWindow);
  72.     __glutSetMenu(__glutMappedMenu);
  73.  
  74.     /* Setting __glutMappedMenu to NULL permits operations that
  75.        change menus or destroy the menu window again. */
  76.     __glutMappedMenu = NULL;
  77.  
  78.     __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y);
  79.   }
  80.   /* Setting __glutMappedMenu to NULL permits operations that
  81.      change menus or destroy the menu window again. */
  82.   __glutMappedMenu = NULL;
  83.  
  84.   /* If an item is selected and it is not a submenu trigger,
  85.      generate menu callback. */
  86.   if (__glutItemSelected && !__glutItemSelected->isTrigger) {
  87.     __glutSetWindow(__glutMenuWindow);
  88.     /* When menu callback is triggered, current menu should be
  89.        set to the callback menu. */
  90.     __glutSetMenu(__glutItemSelected->menu);
  91.     __glutItemSelected->menu->select(__glutItemSelected->value);
  92.   }
  93.   __glutMenuWindow = NULL;
  94. }
  95.  
  96. static void
  97. mapMenu(GLUTmenu * menu, int x, int y)
  98. {
  99.   TrackPopupMenu(menu->win, TPM_LEFTALIGN |
  100.     __glutMenuButton == TPM_RIGHTBUTTON ? 
  101.     TPM_RIGHTBUTTON : TPM_LEFTBUTTON,
  102.     x, y, 0, __glutCurrentWindow->win, NULL);
  103. }
  104.  
  105. void
  106. __glutStartMenu(GLUTmenu * menu, GLUTwindow * window,
  107.         int x, int y, int x_win, int y_win)
  108. {
  109.   assert(__glutMappedMenu == NULL);
  110.   __glutMappedMenu = menu;
  111.   __glutMenuWindow = window;
  112.   __glutItemSelected = NULL;
  113.   if (__glutMenuStatusFunc) {
  114.     __glutSetMenu(menu);
  115.     __glutSetWindow(window);
  116.     __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win);
  117.   }
  118.   mapMenu(menu, x, y);
  119. }
  120.  
  121. GLUTmenuItem *
  122. __glutGetUniqueMenuItem(GLUTmenu * menu, UINT unique)
  123. {
  124.   GLUTmenuItem *item;
  125.   int i;
  126.  
  127.   i = menu->num;
  128.   item = menu->list;
  129.   while (item) {
  130.     if (item->unique == unique) {
  131.       return item;
  132.     }
  133.     if (item->isTrigger) {
  134.       GLUTmenuItem *subitem;
  135.       subitem = __glutGetUniqueMenuItem(menuList[item->value], unique);
  136.       if (subitem) {
  137.         return subitem;
  138.       }
  139.     }
  140.     i--;
  141.     item = item->next;
  142.   }
  143.   return NULL;
  144. }
  145.  
  146. GLUTmenuItem *
  147. __glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
  148. {
  149.   GLUTmenuItem *item;
  150.   int i;
  151.  
  152.   i = menu->num;
  153.   item = menu->list;
  154.   while (item) {
  155.     if (item->win == win) {
  156.       *which = i;
  157.       return item;
  158.     }
  159.     if (item->isTrigger) {
  160.       GLUTmenuItem *subitem;
  161.  
  162.       subitem = __glutGetMenuItem(menuList[item->value],
  163.         win, which);
  164.       if (subitem) {
  165.         return subitem;
  166.       }
  167.     }
  168.     i--;
  169.     item = item->next;
  170.   }
  171.   return NULL;
  172. }
  173.  
  174. GLUTmenu *
  175. __glutGetMenu(Window win)
  176. {
  177.   GLUTmenu *menu;
  178.  
  179.   menu = __glutMappedMenu;
  180.   while (menu) {
  181.     if (win == menu->win) {
  182.       return menu;
  183.     }
  184.     menu = menu->cascade;
  185.   }
  186.   return NULL;
  187. }
  188.  
  189. GLUTmenu *
  190. __glutGetMenuByNum(int menunum)
  191. {
  192.   if (menunum < 1 || menunum > menuListSize) {
  193.     return NULL;
  194.   }
  195.   return menuList[menunum - 1];
  196. }
  197.  
  198. static int
  199. getUnusedMenuSlot(void)
  200. {
  201.   int i;
  202.  
  203.   /* Look for allocated, unused slot. */
  204.   for (i = 0; i < menuListSize; i++) {
  205.     if (!menuList[i]) {
  206.       return i;
  207.     }
  208.   }
  209.   /* Allocate a new slot. */
  210.   menuListSize++;
  211.   if (menuList) {
  212.     menuList = (GLUTmenu **)
  213.       realloc(menuList, menuListSize * sizeof(GLUTmenu *));
  214.   } else {
  215.     /* XXX Some realloc's do not correctly perform a malloc
  216.        when asked to perform a realloc on a NULL pointer,
  217.        though the ANSI C library spec requires this. */
  218.     menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *));
  219.   }
  220.   if (!menuList) {
  221.     __glutFatalError("out of memory.");
  222.   }
  223.   menuList[menuListSize - 1] = NULL;
  224.   return menuListSize - 1;
  225. }
  226.  
  227. static void
  228. menuModificationError(void)
  229. {
  230.   /* XXX Remove the warning after GLUT 3.0. */
  231.   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
  232.   __glutFatalError("menu manipulation not allowed while menus in use.");
  233. }
  234.  
  235. int APIENTRY
  236. glutCreateMenu(GLUTselectCB selectFunc)
  237. {
  238.   GLUTmenu *menu;
  239.   int menuid;
  240.  
  241.   if (__glutMappedMenu) {
  242.     menuModificationError();
  243.   }
  244.   menuid = getUnusedMenuSlot();
  245.   menu = (GLUTmenu *) malloc(sizeof(GLUTmenu));
  246.   if (!menu) {
  247.     __glutFatalError("out of memory.");
  248.   }
  249.   menu->id = menuid;
  250.   menu->num = 0;
  251.   menu->submenus = 0;
  252.   menu->select = selectFunc;
  253.   menu->list = NULL;
  254.   menu->cascade = NULL;
  255.   menu->highlighted = NULL;
  256.   menu->anchor = NULL;
  257.   menu->win = CreatePopupMenu();
  258.   menuList[menuid] = menu;
  259.   __glutSetMenu(menu);
  260.   return menuid + 1;
  261. }
  262.  
  263. void APIENTRY
  264. glutDestroyMenu(int menunum)
  265. {
  266.   GLUTmenu *menu = __glutGetMenuByNum(menunum);
  267.   GLUTmenuItem *item, *next;
  268.  
  269.   if (__glutMappedMenu) {
  270.     menuModificationError();
  271.   }
  272.   assert(menu->id == menunum - 1);
  273.   DestroyMenu(menu->win);
  274.   menuList[menunum - 1] = NULL;
  275.   /* free all menu entries */
  276.   item = menu->list;
  277.   while (item) {
  278.     assert(item->menu == menu);
  279.     next = item->next;
  280.     free(item->label);
  281.     free(item);
  282.     item = next;
  283.   }
  284.   if (__glutCurrentMenu == menu) {
  285.     __glutCurrentMenu = NULL;
  286.   }
  287.   free(menu);
  288. }
  289.  
  290. int APIENTRY
  291. glutGetMenu(void)
  292. {
  293.   if (__glutCurrentMenu) {
  294.     return __glutCurrentMenu->id + 1;
  295.   } else {
  296.     return 0;
  297.   }
  298. }
  299.  
  300. void APIENTRY
  301. glutSetMenu(int menuid)
  302. {
  303.   GLUTmenu *menu;
  304.  
  305.   if (menuid < 1 || menuid > menuListSize) {
  306.     __glutWarning("glutSetMenu attempted on bogus menu.");
  307.     return;
  308.   }
  309.   menu = menuList[menuid - 1];
  310.   if (!menu) {
  311.     __glutWarning("glutSetMenu attempted on bogus menu.");
  312.     return;
  313.   }
  314.   __glutSetMenu(menu);
  315. }
  316.  
  317. static void
  318. setMenuItem(GLUTmenuItem * item, const char *label,
  319.         int value, Bool isTrigger)
  320. {
  321.   GLUTmenu *menu;
  322.  
  323.   menu = item->menu;
  324.   item->label = __glutStrdup(label);
  325.   if (!item->label) {
  326.     __glutFatalError("out of memory.");
  327.   }
  328.   item->isTrigger = isTrigger;
  329.   item->len = (int) strlen(label);
  330.   item->value = value;
  331.   item->unique = uniqueMenuHandler++;
  332.   if (isTrigger) {
  333.     AppendMenu(menu->win, MF_POPUP, (UINT)item->win, label);
  334.   } else {
  335.     AppendMenu(menu->win, MF_STRING, item->unique, label);
  336.   }
  337. }
  338.  
  339. void APIENTRY
  340. glutAddMenuEntry(const char *label, int value)
  341. {
  342.   GLUTmenuItem *entry;
  343.  
  344.   if (__glutMappedMenu) {
  345.     menuModificationError();
  346.   }
  347.   entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
  348.   if (!entry) {
  349.     __glutFatalError("out of memory.");
  350.   }
  351.   entry->menu = __glutCurrentMenu;
  352.   setMenuItem(entry, label, value, FALSE);
  353.   __glutCurrentMenu->num++;
  354.   entry->next = __glutCurrentMenu->list;
  355.   __glutCurrentMenu->list = entry;
  356. }
  357.  
  358. void APIENTRY
  359. glutAddSubMenu(const char *label, int menu)
  360. {
  361.   GLUTmenuItem *submenu;
  362.   GLUTmenu     *popupmenu;
  363.  
  364.   if (__glutMappedMenu) {
  365.     menuModificationError();
  366.   }
  367.   submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
  368.   if (!submenu) {
  369.     __glutFatalError("out of memory.");
  370.   }
  371.   __glutCurrentMenu->submenus++;
  372.   submenu->menu = __glutCurrentMenu;
  373.   popupmenu = __glutGetMenuByNum(menu);
  374.   if (popupmenu) {
  375.     submenu->win = popupmenu->win;
  376.   }
  377.   setMenuItem(submenu, label, /* base 0 */ menu - 1, TRUE);
  378.   __glutCurrentMenu->num++;
  379.   submenu->next = __glutCurrentMenu->list;
  380.   __glutCurrentMenu->list = submenu;
  381. }
  382.  
  383. void APIENTRY
  384. glutChangeToMenuEntry(int num, const char *label, int value)
  385. {
  386.   GLUTmenuItem *item;
  387.   int i;
  388.  
  389.   if (__glutMappedMenu) {
  390.     menuModificationError();
  391.   }
  392.   i = __glutCurrentMenu->num;
  393.   item = __glutCurrentMenu->list;
  394.   while (item) {
  395.     if (i == num) {
  396.       if (item->isTrigger) {
  397.         /* If changing a submenu trigger to a menu entry, we
  398.            need to account for submenus.  */
  399.         item->menu->submenus--;
  400.     /* Nuke the Win32 menu. */
  401.     DestroyMenu(item->win);        
  402.       }
  403.       free(item->label);
  404.  
  405.       item->label = strdup(label);
  406.       if (!item->label)
  407.     __glutFatalError("out of memory");
  408.       item->isTrigger = FALSE;
  409.       item->len = (int) strlen(label);
  410.       item->value = value;
  411.       item->unique = uniqueMenuHandler++;
  412.       ModifyMenu(__glutCurrentMenu->win, (UINT) i - 1,
  413.         MF_BYPOSITION | MFT_STRING, item->unique, label);
  414.  
  415.       return;
  416.     }
  417.     i--;
  418.     item = item->next;
  419.   }
  420.   __glutWarning("Current menu has no %d item.", num);
  421. }
  422.  
  423. void APIENTRY
  424. glutChangeToSubMenu(int num, const char *label, int menu)
  425. {
  426.   GLUTmenu *popupmenu;
  427.   GLUTmenuItem *item;
  428.   int i;
  429.  
  430.   if (__glutMappedMenu) {
  431.     menuModificationError();
  432.   }
  433.   i = __glutCurrentMenu->num;
  434.   item = __glutCurrentMenu->list;
  435.   while (item) {
  436.     if (i == num) {
  437.       if (!item->isTrigger) {
  438.         /* If changing a menu entry to as submenu trigger, we
  439.            need to account for submenus.  */
  440.         item->menu->submenus++;
  441.     item->win = CreatePopupMenu();
  442.       }
  443.       free(item->label);
  444.       
  445.       item->label = strdup(label);
  446.       if (!item->label)
  447.     __glutFatalError("out of memory");
  448.       item->isTrigger = TRUE;
  449.       item->len = (int) strlen(label);
  450.       item->value = menu - 1;
  451.       item->unique = uniqueMenuHandler++;
  452.       popupmenu = __glutGetMenuByNum(menu);
  453.       if (popupmenu)
  454.     item->win = popupmenu->win;
  455.       ModifyMenu(__glutCurrentMenu->win, (UINT) i - 1,
  456.         MF_BYPOSITION | MF_POPUP, (UINT) item->win, label);
  457.       return;
  458.     }
  459.     i--;
  460.     item = item->next;
  461.   }
  462.   __glutWarning("Current menu has no %d item.", num);
  463. }
  464.  
  465. void APIENTRY
  466. glutRemoveMenuItem(int num)
  467. {
  468.   GLUTmenuItem *item, **prev;
  469.   int i;
  470.  
  471.   if (__glutMappedMenu) {
  472.     menuModificationError();
  473.   }
  474.   i = __glutCurrentMenu->num;
  475.   prev = &__glutCurrentMenu->list;
  476.   item = __glutCurrentMenu->list;
  477.   while (item) {
  478.     if (i == num) {
  479.       /* Found the menu item in list to remove. */
  480.       __glutCurrentMenu->num--;
  481.  
  482.       /* Patch up menu's item list. */
  483.       *prev = item->next;
  484.  
  485.       RemoveMenu(__glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION);
  486.  
  487.       free(item->label);
  488.       free(item);
  489.       return;
  490.     }
  491.     i--;
  492.     prev = &item->next;
  493.     item = item->next;
  494.   }
  495.   __glutWarning("Current menu has no %d item.", num);
  496. }
  497.  
  498. void APIENTRY
  499. glutAttachMenu(int button)
  500. {
  501.   if (__glutCurrentWindow == __glutGameModeWindow) {
  502.     __glutWarning("cannot attach menus in game mode.");
  503.     return;
  504.   }
  505.   if (__glutMappedMenu) {
  506.     menuModificationError();
  507.   }
  508.   if (__glutCurrentWindow->menu[button] < 1) {
  509.     __glutCurrentWindow->buttonUses++;
  510.   }
  511.   __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;
  512. }
  513.  
  514. void APIENTRY
  515. glutDetachMenu(int button)
  516. {
  517.   if (__glutMappedMenu) {
  518.     menuModificationError();
  519.   }
  520.   if (__glutCurrentWindow->menu[button] > 0) {
  521.     __glutCurrentWindow->buttonUses--;
  522.     __glutCurrentWindow->menu[button] = 0;
  523.   }
  524. }
  525.  
  526.